package com.amar.dtadmin.apidoc.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.amar.dtadmin.apidoc.model.ApiDocCreateReq;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author xiaoshiqiang
 * @since 2025/2/10
 */
public class ParamItemConvertUtil {

    public static List<ApiDocCreateReq.ParamItem> convert(PsiClass psiClass, String paramType) {
        return convert(psiClass, paramType, 0, null, 0);
    }

    public static List<ApiDocCreateReq.ParamItem> convert(PsiClass psiClass, String paramType, int level, String parentId, int recursionChildLevel) {
        List<PsiField> fields = getAllJavaBeanProperties(psiClass);
        AtomicInteger sortNo = new AtomicInteger(1);
        return fields.stream().map(field -> {
            PsiTypeUtil.FieldInfo fieldInfo = PsiTypeUtil.getFieldInfo(field);
            if (fieldInfo != null) {
                ApiDocCreateReq.ParamItem item = new ApiDocCreateReq.ParamItem();
                item.setSortno(sortNo.getAndIncrement());
                item.setName(fieldInfo.getFieldName());
                item.setChname(fieldInfo.getFieldDocument());
                item.setDatatype(fieldInfo.getFieldType());
                item.setIsrequired(fieldInfo.getIsRequired());
                item.setLevel(level);
                item.setParamtype(paramType);
                item.setId(StrUtil.isEmpty(parentId) ? String.valueOf(item.getSortno()) : parentId + "-" + item.getSortno());
                if (fieldInfo.getTypeClass() != null) {
                    String parentClassName = psiClass.getQualifiedName();
                    String currentClassname = fieldInfo.getTypeClass().getQualifiedName();
                    // 如果字段有递归层级，则只设置一层就行

                    if (!(StrUtil.equals(parentClassName, currentClassname) && recursionChildLevel > 0)) {
                        if (StrUtil.equals(parentClassName, currentClassname)) {
                            item.setNextnode(convert(fieldInfo.getTypeClass(), paramType, level + 1, item.getId(), recursionChildLevel + 1));
                        } else {
                            item.setNextnode(convert(fieldInfo.getTypeClass(), paramType, level + 1, item.getId(), 0));
                        }
                    }
                }
                return item;
            }
            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 获取 JavaBean 的所有属性，包括父类的属性
     *
     * @param psiClass 要检查的 PsiClass
     * @return 属性列表
     */
    public static List<PsiField> getAllJavaBeanProperties(PsiClass psiClass) {
        List<PsiField> properties = new ArrayList<>();
        if (psiClass != null && PsiTypeUtil.isJavaBean(psiClass)) {
            collectPropertiesRecursively(psiClass, properties);
        }
        return properties;
    }

    /**
     * 检查字段是否有对应的 getter 和 setter 方法
     *
     * @param psiClass  类
     * @param fieldName 字段名
     * @return 如果有对应的 getter 和 setter 方法返回 true，否则返回 false
     */
    private static boolean hasGetterAndSetter(PsiClass psiClass, String fieldName) {
        boolean hasGetter = false;
        boolean hasSetter = false;
        PsiMethod[] methods = psiClass.getMethods();
        for (PsiMethod method : methods) {
            String methodName = method.getName();
            if (methodName.startsWith("get") || methodName.startsWith("is")) {
                String accessorFieldName = PsiTypeUtil.getFieldNameFromAccessor(methodName);
                if (accessorFieldName.equals(fieldName)) {
                    hasGetter = true;
                }
            } else if (methodName.startsWith("set")) {
                String accessorFieldName = PsiTypeUtil.getFieldNameFromAccessor(methodName);
                if (accessorFieldName.equals(fieldName)) {
                    hasSetter = true;
                }
            }
        }
        return hasGetter && hasSetter;
    }

    /**
     * 对比当前生成接口文档与平台上接口文档
     * 1、对于都存在的字段将nodeId填充到当前生成的文档中
     * 2、找出平台上比当前生成文档多出的字段
     *
     * @param current 要推送平台更新的数据
     * @param history 平台上已经存在的数据
     * @return 平台上比推送多出的字段
     */
    public static List<String> compareUpdateApiDoc(List<ApiDocCreateReq.ParamItem> current, List<ApiDocCreateReq.ParamItem> history, String parentNodeId) {
        List<String> delNodeIds = new ArrayList<>();
        Map<String, ApiDocCreateReq.ParamItem> historyMap = history.stream().collect(Collectors.toMap(ApiDocCreateReq.ParamItem::getName, Function.identity()));
        Set<String> nodeIdSet = historyMap.values().stream().map(ApiDocCreateReq.ParamItem::getNodeid).collect(Collectors.toSet());
        current.forEach((node) -> {
            node.setParentnodeid(parentNodeId);
            ApiDocCreateReq.ParamItem historyNode = historyMap.get(node.getName());
            if (historyNode != null) {
                String nodeId = historyNode.getNodeid();
                nodeIdSet.remove(nodeId);
                node.setNodeid(nodeId);
            }
            if (CollUtil.isNotEmpty(node.getNextnode()) || (historyNode != null && CollUtil.isNotEmpty(historyNode.getNextnode()))) {
                String nodeId = historyNode == null ? null : historyNode.getNodeid();
                List<ApiDocCreateReq.ParamItem> currentList = CollUtil.emptyIfNull(node.getNextnode());
                List<ApiDocCreateReq.ParamItem> historyList = historyNode == null ? Collections.emptyList() : CollUtil.emptyIfNull(historyNode.getNextnode());
                List<String> nextDelNodeIds = compareUpdateApiDoc(currentList, historyList, nodeId);
                delNodeIds.addAll(nextDelNodeIds);
            }
        });
        delNodeIds.addAll(nodeIdSet);
        return delNodeIds;
    }

    /**
     * 递归收集类及其父类的属性
     *
     * @param psiClass   当前类
     * @param properties 存储属性的列表
     */
    private static void collectPropertiesRecursively(PsiClass psiClass, List<PsiField> properties) {
        if (psiClass == null) {
            return;
        }
        PsiField[] fields = psiClass.getFields();
        for (PsiField field : fields) {
            PsiAnnotation annotation = PsiAnnotationUtil.getAnnotation(field, "com.alibaba.fastjson.annotation.JSONField");
            boolean serialize = annotation == null || Boolean.TRUE.equals(PsiAnnotationUtil.getAnnotationValue(annotation, "serialize"));
            if (serialize && !field.hasModifierProperty(PsiModifier.TRANSIENT) && hasGetterAndSetter(psiClass, field.getName())) {
                properties.add(field);
            }
        }
        // 递归处理父类
        PsiClass superClass = psiClass.getSuperClass();
        collectPropertiesRecursively(superClass, properties);
    }
}
